/*
 * PostgreSQL 对 INET 和 CIDR 类型的定义。
 *
 *	src/backend/utils/adt/network.c
 *
 *	Jon Postel 依依惜别 1998年10月16日
 */

#include "postgres.h"

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "access/stratnum.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_type.h"
#include "common/hashfn.h"
#include "common/ip.h"
#include "lib/hyperloglog.h"
#include "libpq/libpq-be.h"
#include "libpq/pqformat.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "nodes/supportnodes.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/guc.h"
#include "utils/inet.h"
#include "utils/lsyscache.h"
#include "utils/sortsupport.h"


/*
 * IPv4 网络掩码大小是 0 - 32 范围内的值，
 * 在可能的情况下使用 6 位表示 inet/cidr 缩写键。
 *
 * IPv4 inet/cidr 缩写键最多可以使用 25 位表示子网
 * 组件。
 */
#define ABBREV_BITS_INET4_NETMASK_SIZE	6
#define ABBREV_BITS_INET4_SUBNET		25

/* inet/cidr 的排序支持 */
typedef struct
{
	int64		input_count;	/* 看到的非空值数量 */
	bool		estimating;		/* 如果估计基数为真 */

	hyperLogLogState abbr_card; /* 基数估算器 */
} network_sortsupport_state;

static int32 fc_network_cmp_internal(inet *fc_a1, inet *fc_a2);
static int	fc_network_fast_cmp(Datum fc_x, Datum fc_y, SortSupport fc_ssup);
static bool fc_network_abbrev_abort(int fc_memtupcount, SortSupport fc_ssup);
static Datum fc_network_abbrev_convert(Datum fc_original, SortSupport fc_ssup);
static List *fc_match_network_function(Node *fc_leftop,
									Node *fc_rightop,
									int fc_indexarg,
									Oid fc_funcid,
									Oid fc_opfamily);
static List *fc_match_network_subset(Node *fc_leftop,
								  Node *fc_rightop,
								  bool fc_is_eq,
								  Oid fc_opfamily);
static bool fc_addressOK(unsigned char *fc_a, int fc_bits, int fc_family);
static inet *fc_internal_inetpl(inet *fc_ip, int64 fc_addend);


/*
 * 通用 INET/CIDR 输入例程
 */
static inet * fc_network_in(char *fc_src, bool fc_is_cidr)
{
	int			fc_bits;
	inet	   *fc_dst;

	fc_dst = (inet *) palloc0(sizeof(inet));

	/*
	 * 首先，检查这是否是 IPv6 或 IPv4 地址。IPv6 地址
	 * 将在某个位置包含 : （实际上是多个），因此如果出现一个
	 * ，假设它是 V6，否则假设它是 V4。
	 */

	if (strchr(fc_src, ':') != NULL)
		ip_family(fc_dst) = PGSQL_AF_INET6;
	else
		ip_family(fc_dst) = PGSQL_AF_INET;

	fc_bits = pg_inet_net_pton(ip_family(fc_dst), fc_src, ip_addr(fc_dst),
							fc_is_cidr ? ip_addrsize(fc_dst) : -1);
	if ((fc_bits < 0) || (fc_bits > ip_maxbits(fc_dst)))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
		/* 翻译者：第一个 %s 是 inet 或 cidr */
				 errmsg("invalid input syntax for type %s: \"%s\"",
						fc_is_cidr ? "cidr" : "inet", fc_src)));

	/*
	 * 错误检查：CIDR 值不得有任何超出掩码长度的位被设置。
	 */
	if (fc_is_cidr)
	{
		if (!fc_addressOK(ip_addr(fc_dst), fc_bits, ip_family(fc_dst)))
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
					 errmsg("invalid cidr value: \"%s\"", fc_src),
					 errdetail("Value has bits set to right of mask.")));
	}

	ip_bits(fc_dst) = fc_bits;
	SET_INET_VARSIZE(fc_dst);

	return fc_dst;
}

Datum inet_in(PG_FUNCTION_ARGS)
{
	char	   *fc_src = PG_GETARG_CSTRING(0);

	PG_RETURN_INET_P(fc_network_in(fc_src, false));
}

Datum cidr_in(PG_FUNCTION_ARGS)
{
	char	   *fc_src = PG_GETARG_CSTRING(0);

	PG_RETURN_INET_P(fc_network_in(fc_src, true));
}


/*
 * 通用 INET/CIDR 输出例程
 */
static char * fc_network_out(inet *fc_src, bool fc_is_cidr)
{
	char		fc_tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
	char	   *fc_dst;
	int			fc_len;

	fc_dst = pg_inet_net_ntop(ip_family(fc_src), ip_addr(fc_src), ip_bits(fc_src),
						   fc_tmp, sizeof(fc_tmp));
	if (fc_dst == NULL)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
				 errmsg("could not format inet value: %m")));

	/* 对于 CIDR，如果没有 /n 则添加 */
	if (fc_is_cidr && strchr(fc_tmp, '/') == NULL)
	{
		fc_len = strlen(fc_tmp);
		snprintf(fc_tmp + fc_len, sizeof(fc_tmp) - fc_len, "/%u", ip_bits(fc_src));
	}

	return pstrdup(fc_tmp);
}

Datum inet_out(PG_FUNCTION_ARGS)
{
	inet	   *fc_src = PG_GETARG_INET_PP(0);

	PG_RETURN_CSTRING(fc_network_out(fc_src, false));
}

Datum cidr_out(PG_FUNCTION_ARGS)
{
	inet	   *fc_src = PG_GETARG_INET_PP(0);

	PG_RETURN_CSTRING(fc_network_out(fc_src, true));
}


/*
 *		network_recv		- 将外部二进制格式转换为 inet
 *
 * 外部表示为（每个字节一个）
 * family, bits, is_cidr, 地址长度, 网络字节序的地址。
 *
 * is_cidr 的存在主要出于历史原因，尽管这可能
 * 允许客户端的一些代码共享。我们在输出时正确发送它，
 * 但在输入时忽略该值。
 */
static inet * fc_network_recv(StringInfo fc_buf, bool fc_is_cidr)
{
	inet	   *fc_addr;
	char	   *fc_addrptr;
	int			fc_bits;
	int			fc_nb,
				fc_i;

	/* 确保 CIDR 值中未使用的位被置为零 */
	fc_addr = (inet *) palloc0(sizeof(inet));

	ip_family(fc_addr) = pq_getmsgbyte(fc_buf);
	if (ip_family(fc_addr) != PGSQL_AF_INET &&
		ip_family(fc_addr) != PGSQL_AF_INET6)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
		/* 翻译者：%s 是 inet 或 cidr */
				 errmsg("invalid address family in external \"%s\" value",
						fc_is_cidr ? "cidr" : "inet")));
	fc_bits = pq_getmsgbyte(fc_buf);
	if (fc_bits < 0 || fc_bits > ip_maxbits(fc_addr))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
		/* 翻译者：%s 是 inet 或 cidr */
				 errmsg("invalid bits in external \"%s\" value",
						fc_is_cidr ? "cidr" : "inet")));
	ip_bits(fc_addr) = fc_bits;
	fc_i = pq_getmsgbyte(fc_buf);		/* 忽略 is_cidr */
	fc_nb = pq_getmsgbyte(fc_buf);
	if (fc_nb != ip_addrsize(fc_addr))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
		/* 翻译者：%s 是 inet 或 cidr */
				 errmsg("invalid length in external \"%s\" value",
						fc_is_cidr ? "cidr" : "inet")));

	fc_addrptr = (char *) ip_addr(fc_addr);
	for (fc_i = 0; fc_i < fc_nb; fc_i++)
		fc_addrptr[fc_i] = pq_getmsgbyte(fc_buf);

	/*
	 * 错误检查：CIDR 值不得有任何超出掩码长度的位被设置。
	 */
	if (fc_is_cidr)
	{
		if (!fc_addressOK(ip_addr(fc_addr), fc_bits, ip_family(fc_addr)))
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
					 errmsg("invalid external \"cidr\" value"),
					 errdetail("Value has bits set to right of mask.")));
	}

	SET_INET_VARSIZE(fc_addr);

	return fc_addr;
}

Datum inet_recv(PG_FUNCTION_ARGS)
{
	StringInfo	fc_buf = (StringInfo) PG_GETARG_POINTER(0);

	PG_RETURN_INET_P(fc_network_recv(fc_buf, false));
}

Datum cidr_recv(PG_FUNCTION_ARGS)
{
	StringInfo	fc_buf = (StringInfo) PG_GETARG_POINTER(0);

	PG_RETURN_INET_P(fc_network_recv(fc_buf, true));
}


/*
 *		network_send		- 将 inet 转换为二进制格式
 */
static bytea * fc_network_send(inet *fc_addr, bool fc_is_cidr)
{
	StringInfoData fc_buf;
	char	   *fc_addrptr;
	int			fc_nb,
				fc_i;

	pq_begintypsend(&fc_buf);
	pq_sendbyte(&fc_buf, ip_family(fc_addr));
	pq_sendbyte(&fc_buf, ip_bits(fc_addr));
	pq_sendbyte(&fc_buf, fc_is_cidr);
	fc_nb = ip_addrsize(fc_addr);
	if (fc_nb < 0)
		fc_nb = 0;
	pq_sendbyte(&fc_buf, fc_nb);
	fc_addrptr = (char *) ip_addr(fc_addr);
	for (fc_i = 0; fc_i < fc_nb; fc_i++)
		pq_sendbyte(&fc_buf, fc_addrptr[fc_i]);
	return pq_endtypsend(&fc_buf);
}

Datum inet_send(PG_FUNCTION_ARGS)
{
	inet	   *fc_addr = PG_GETARG_INET_PP(0);

	PG_RETURN_BYTEA_P(fc_network_send(fc_addr, false));
}

Datum cidr_send(PG_FUNCTION_ARGS)
{
	inet	   *fc_addr = PG_GETARG_INET_PP(0);

	PG_RETURN_BYTEA_P(fc_network_send(fc_addr, true));
}


Datum inet_to_cidr(PG_FUNCTION_ARGS)
{
	inet	   *fc_src = PG_GETARG_INET_PP(0);
	int			fc_bits;

	fc_bits = ip_bits(fc_src);

	/* 安全检查 */
	if ((fc_bits < 0) || (fc_bits > ip_maxbits(fc_src)))
		elog(ERROR, "invalid inet bit length: %d", fc_bits);

	PG_RETURN_INET_P(cidr_set_masklen_internal(fc_src, fc_bits));
}

Datum inet_set_masklen(PG_FUNCTION_ARGS)
{
	inet	   *fc_src = PG_GETARG_INET_PP(0);
	int			fc_bits = PG_GETARG_INT32(1);
	inet	   *fc_dst;

	if (fc_bits == -1)
		fc_bits = ip_maxbits(fc_src);

	if ((fc_bits < 0) || (fc_bits > ip_maxbits(fc_src)))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("invalid mask length: %d", fc_bits)));

	/* 克隆原始数据 */
	fc_dst = (inet *) palloc(VARSIZE_ANY(fc_src));
	memcpy(fc_dst, fc_src, VARSIZE_ANY(fc_src));

	ip_bits(fc_dst) = fc_bits;

	PG_RETURN_INET_P(fc_dst);
}

Datum cidr_set_masklen(PG_FUNCTION_ARGS)
{
	inet	   *fc_src = PG_GETARG_INET_PP(0);
	int			fc_bits = PG_GETARG_INT32(1);

	if (fc_bits == -1)
		fc_bits = ip_maxbits(fc_src);

	if ((fc_bits < 0) || (fc_bits > ip_maxbits(fc_src)))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("invalid mask length: %d", fc_bits)));

	PG_RETURN_INET_P(cidr_set_masklen_internal(fc_src, fc_bits));
}

/*
 * 复制 src 并将掩码长度设置为 'bits'（这必须对 family 有效）
 */
inet *
cidr_set_masklen_internal(const inet *fc_src, int fc_bits)
{
	inet	   *fc_dst = (inet *) palloc0(sizeof(inet));

	ip_family(fc_dst) = ip_family(fc_src);
	ip_bits(fc_dst) = fc_bits;

	if (fc_bits > 0)
	{
		Assert(fc_bits <= ip_maxbits(fc_dst));

		/* 克隆地址的适当字节，其余部分置为 0 */
		memcpy(ip_addr(fc_dst), ip_addr(fc_src), (fc_bits + 7) / 8);

		/* 清除最后一个部分字节中任何不需要的位 */
		if (fc_bits % 8)
			ip_addr(fc_dst)[fc_bits / 8] &= ~(0xFF >> (fc_bits % 8));
	}

	/* 正确设置 varlena 头 */
	SET_INET_VARSIZE(fc_dst);

	return fc_dst;
}

/*
 * 用于排序和 inet/cidr 比较的基本比较函数。
 *
 * 比较首先是网络部分的公共位，然后是网络部分的长度，
 * 然后是整个未掩码的地址。效果是网络部分是主要的排序键，
 * 对于相等的网络部分，我们在主机部分排序。请注意，这仅在
 * CIDR 中是合理的，前提是掩码右侧的地址位必须保证为零；
 * 否则逻辑上相等的 CIDR 可能比较不同。
 */

static int32 fc_network_cmp_internal(inet *fc_a1, inet *fc_a2)
{
	if (ip_family(fc_a1) == ip_family(fc_a2))
	{
		int			fc_order;

		fc_order = bitncmp(ip_addr(fc_a1), ip_addr(fc_a2),
						Min(ip_bits(fc_a1), ip_bits(fc_a2)));
		if (fc_order != 0)
			return fc_order;
		fc_order = ((int) ip_bits(fc_a1)) - ((int) ip_bits(fc_a2));
		if (fc_order != 0)
			return fc_order;
		return bitncmp(ip_addr(fc_a1), ip_addr(fc_a2), ip_maxbits(fc_a1));
	}

	return ip_family(fc_a1) - ip_family(fc_a2);
}

Datum network_cmp(PG_FUNCTION_ARGS)
{
	inet	   *fc_a1 = PG_GETARG_INET_PP(0);
	inet	   *fc_a2 = PG_GETARG_INET_PP(1);

	PG_RETURN_INT32(fc_network_cmp_internal(fc_a1, fc_a2));
}

/*
 * SortSupport 策略例程
 */
Datum network_sortsupport(PG_FUNCTION_ARGS)
{
	SortSupport fc_ssup = (SortSupport) PG_GETARG_POINTER(0);

	fc_ssup->comparator = fc_network_fast_cmp;
	fc_ssup->ssup_extra = NULL;

	if (fc_ssup->abbreviate)
	{
		network_sortsupport_state *fc_uss;
		MemoryContext fc_oldcontext;

		fc_oldcontext = MemoryContextSwitchTo(fc_ssup->ssup_cxt);

		fc_uss = palloc(sizeof(network_sortsupport_state));
		fc_uss->input_count = 0;
		fc_uss->estimating = true;
		initHyperLogLog(&fc_uss->abbr_card, 10);

		fc_ssup->ssup_extra = fc_uss;

		fc_ssup->comparator = ssup_datum_unsigned_cmp;
		fc_ssup->abbrev_converter = fc_network_abbrev_convert;
		fc_ssup->abbrev_abort = fc_network_abbrev_abort;
		fc_ssup->abbrev_full_comparator = fc_network_fast_cmp;

		MemoryContextSwitchTo(fc_oldcontext);
	}

	PG_RETURN_VOID();
}

/*
 * SortSupport 比较函数
 */
static int fc_network_fast_cmp(Datum fc_x, Datum fc_y, SortSupport fc_ssup)
{
	inet	   *fc_arg1 = DatumGetInetPP(fc_x);
	inet	   *fc_arg2 = DatumGetInetPP(fc_y);

	return fc_network_cmp_internal(fc_arg1, fc_arg2);
}

/*
 * 用于估算缩写键优化效果的回调。
 *
 * 我们不关注未缩略数据的基数，因为
 * 在权威的 inet 比较器中没有快速路径。
 */
static bool fc_network_abbrev_abort(int fc_memtupcount, SortSupport fc_ssup)
{
	network_sortsupport_state *fc_uss = fc_ssup->ssup_extra;
	double		fc_abbr_card;

	if (fc_memtupcount < 10000 || fc_uss->input_count < 10000 || !fc_uss->estimating)
		return false;

	fc_abbr_card = estimateHyperLogLog(&fc_uss->abbr_card);

	/*
	 * 如果我们有超过 100k 的不同值，那么即使我们对许多
	 * 亿行进行排序，我们仍然可能会持平，撤销那么多缩略行的罚款
	 * 可能也不值得。在这一点上，我们停止计数，因为我们知道
	 * 我们现在已经完全承诺。
	 */
	if (fc_abbr_card > 100000.0)
	{
#ifdef TRACE_SORT
		if (trace_sort)
			elog(LOG,
				 "network_abbrev: estimation ends at cardinality %f"
				 " after " INT64_FORMAT " values (%d rows)",
				 fc_abbr_card, fc_uss->input_count, fc_memtupcount);
#endif
		fc_uss->estimating = false;
		return false;
	}

	/*
	 * 目标最小基数为每 ~2k 的非空输入 1。0.5 行的
	 * 允许因子使我们能够在真正病态的数据上更早中止，
	 * 在前 2k（非空）行中只有一个缩略值。
	 */
	if (fc_abbr_card < fc_uss->input_count / 2000.0 + 0.5)
	{
#ifdef TRACE_SORT
		if (trace_sort)
			elog(LOG,
				 "network_abbrev: aborting abbreviation at cardinality %f"
				 " below threshold %f after " INT64_FORMAT " values (%d rows)",
				 fc_abbr_card, fc_uss->input_count / 2000.0 + 0.5, fc_uss->input_count,
				 fc_memtupcount);
#endif
		return true;
	}

#ifdef TRACE_SORT
	if (trace_sort)
		elog(LOG,
			 "network_abbrev: cardinality %f after " INT64_FORMAT
			 " values (%d rows)", fc_abbr_card, fc_uss->input_count, fc_memtupcount);
#endif

	return false;
}


/*
 * SortSupport 转换例程。将原始 inet/cidr 表示转换为简化的键表示，适用于简单的 3-way 无符号整数比较。排序 inet/cidr 数据的 network_cmp_internal() 规则通过编码方案遵循简化比较，这种方案通过谨慎使用填充来调节键。
 *
 * 背景信息：inet 值有三个主要组件（以地址 1.2.3.4/24 为例）：
 *
 *     * 一个网络，或网络掩码位 (1.2.3.0)。
 *     * 一个网络掩码大小 (/24)。
 *     * 一个子网，或网络掩码外的位 (0.0.0.4)。
 *
 * cidr 值与此相同，但只有前两个组件——所有子网位 *必须* 为零 (1.2.3.0/24)。
 *
 * IPv4 和 IPv6 在这方面是相同的，唯一的区别是 IPv4 地址的最大位数为 32 位，而 IPv6 为 64 位，因此在 IPv6 中每个部分可能更大。
 *
 * inet/cidr 类型使用这些排序规则进行比较。如果在任何步骤检测到不平等，比较就结束了。如果任何规则是平局，算法将继续查找下一个以打破平局：
 *
 *     1. IPv4 总是出现在 IPv6 之前。
 *     2. 比较网络位。
 *     3. 比较网络掩码大小。
 *     4. 比较所有位（在此处已经确认网络掩码位和网络掩码大小相等，因此实际上我们仅比较子网位）。
 *
 * 在为 SortSupport 生成简化键时，我们尽可能多地将数据压缩到数据项中，同时确保在将这些键作为整数进行比较时，将遵循这些规则。确切内容取决于 IP 家族和数据项大小。
 *
 * IPv4
 * ----
 *
 * 4 字节数据项：
 *
 * 从 1 位 IP 家族（IPv4 或 IPv6; 该位在下面的每个案例中都存在）开始，后面跟随所有但 1 的网络掩码位。
 *
 * +----------+---------------------+
 * | 1 位 IP  |   31 位网络        |     （省略 1 位网络
 * |  家族    |     （截断）       |      )
 * +----------+---------------------+
 *
 * 8 字节数据项：
 *
 * 我们有空间存储所有网络掩码位，后跟网络掩码大小，再后面是 25 位子网（25 位在实践中通常足够）。cidr 数据项的所有子网位始终为全零。
 *
 * +----------+-----------------------+--------------+--------------------+
 * | 1 位 IP  |    32 位网络         |    6 位      |   25 位子网       |
 * |  家族    |        （完整）      | 网络大小     |    （截断）        |
 * +----------+-----------------------+--------------+--------------------+
 *
 * IPv6
 * ----
 *
 * 4 字节数据项：
 *
 * +----------+---------------------+
 * | 1 位 IP  |   31 位网络        |    （最多 97 位
 * |  家族    |     （截断）       |   网络省略）
 * +----------+---------------------+
 *
 * 8 字节数据项：
 *
 * +----------+---------------------------------+
 * | 1 位 IP  |         63 位网络              |    （最多 65 位
 * |  家族    |           （截断）             |   网络省略）
 * +----------+---------------------------------+
 */
static Datum fc_network_abbrev_convert(Datum fc_original, SortSupport fc_ssup)
{
	network_sortsupport_state *fc_uss = fc_ssup->ssup_extra;
	inet	   *fc_authoritative = DatumGetInetPP(fc_original);
	Datum		fc_res,
				fc_ipaddr_datum,
				fc_subnet_bitmask,
				fc_network;
	int			fc_subnet_size;

	Assert(ip_family(fc_authoritative) == PGSQL_AF_INET ||
		   ip_family(fc_authoritative) == PGSQL_AF_INET6);

	/*
	 * 通过获取 IP 地址的前 4 或 8 字节来获取无符号整数表示。始终取 IPv4 地址的所有 4 字节。对于 IPv6 地址，使用 8 字节数据项时取前 8 字节，否则取 4 字节。
	 *
	 * 我们正在处理一个无符号字符数组，因此在小端系统上进行字节交换（inet 的 ipaddr 字段首先存储最高有效字节）。
	 */
	if (ip_family(fc_authoritative) == PGSQL_AF_INET)
	{
		uint32		fc_ipaddr_datum32;

		memcpy(&fc_ipaddr_datum32, ip_addr(fc_authoritative), sizeof(uint32));

		/* 在小端机器上必须进行字节交换 */
#ifndef WORDS_BIGENDIAN
		fc_ipaddr_datum = pg_bswap32(fc_ipaddr_datum32);
#else
		fc_ipaddr_datum = fc_ipaddr_datum32;
#endif

		/* 在不设置 ipfamily 位的情况下初始化结果 */
		fc_res = (Datum) 0;
	}
	else
	{
		memcpy(&fc_ipaddr_datum, ip_addr(fc_authoritative), sizeof(Datum));

		/* 在小端机器上必须进行字节交换 */
		fc_ipaddr_datum = DatumBigEndianToNative(fc_ipaddr_datum);

		/* 初始化结果，设置 ipfamily（最高有效）位 */
		fc_res = ((Datum) 1) << (SIZEOF_DATUM * BITS_PER_BYTE - 1);
	}

	/*
	 * ipaddr_datum 必须是“分开的”：高位放入简化键的“网络”组件中（由于掩码，通常在末尾为零），而低位放入“子网”组件中（当有空间时）。这通常通过生成一个临时数据项子网位掩码来完成，稍后在生成子网位时可以重用。（注意，子网位仅在数据项为 8 字节的平台上与 IPv4 数据项一起使用。）
	 *
	 * 子网中的位数用于生成一个数据项子网位掩码。例如，对于 /24 的 IPv4 数据项，有 8 个子网位（因为 32 - 24 等于 8），因此最终子网位掩码为 B'1111 1111'。不过，我们需要专门处理那些 ipaddr 位不能完全适合一个数据项的情况（否则我们将错误地使用 IPv6 值掩码网络组件）。
	 */
	fc_subnet_size = ip_maxbits(fc_authoritative) - ip_bits(fc_authoritative);
	Assert(fc_subnet_size >= 0);
	/* 子网大小必须与前缀 ipaddr 情况一起工作 */
	fc_subnet_size %= SIZEOF_DATUM * BITS_PER_BYTE;
	if (ip_bits(fc_authoritative) == 0)
	{
		/* 尽可能将 ipaddr 位适配到子网 */
		fc_subnet_bitmask = ((Datum) 0) - 1;
		fc_network = 0;
	}
	else if (ip_bits(fc_authoritative) < SIZEOF_DATUM * BITS_PER_BYTE)
	{
		/* 将 ipaddr 位拆分到网络和子网中 */
		fc_subnet_bitmask = (((Datum) 1) << fc_subnet_size) - 1;
		fc_network = fc_ipaddr_datum & ~fc_subnet_bitmask;
	}
	else
	{
		/* 尽可能将 ipaddr 位适配到网络 */
		fc_subnet_bitmask = 0;
		fc_network = fc_ipaddr_datum;
	}

#if SIZEOF_DATUM == 8
	if (ip_family(fc_authoritative) == PGSQL_AF_INET)
	{
		/*
		 * 使用 8 字节数据项的 IPv4：保留所有 32 位网络掩码位、网络掩码大小，以及最重要的 25 位子网位
		 */
		Datum		fc_netmask_size = (Datum) ip_bits(fc_authoritative);
		Datum		fc_subnet;

		
/*
		 * 左移31位：6位子网掩码大小 + 25位子网位。
		 *
		 * 我们没有区分由于掩码而变为零的网络位和“真实的”/非掩码的零位。一个简化的
		 * 比较通过将一个非掩码和非零位与一个掩码/零位进行比较有效地解决，
		 * 尽管比较不会达到子网掩码大小位。
		 */
		fc_network <<= (ABBREV_BITS_INET4_NETMASK_SIZE +
					 ABBREV_BITS_INET4_SUBNET);

		/* 调整大小以为末尾的子网位留出空间 */
		fc_netmask_size <<= ABBREV_BITS_INET4_SUBNET;

		/* 提取子网位而不进行位移 */
		fc_subnet = fc_ipaddr_datum & fc_subnet_bitmask;

		/*
		 * 如果我们有超过25个子网位，我们无法容纳所有内容。将
		 * 子网下移以避免覆盖仅用于 netmask_size 的位。
		 *
		 * 像这样丢弃最低有效的子网位是正确的，因为在子网
		 * 级别解决的简写比较必须具有相等的 netmask_size/ip_bits() 值，才能到达这一步。
		 */
		if (fc_subnet_size > ABBREV_BITS_INET4_SUBNET)
			fc_subnet >>= fc_subnet_size - ABBREV_BITS_INET4_SUBNET;

		/*
		 * 组装最终的简写键，而不覆盖必须保持为零的 ipfamily
		 * 位。
		 */
		fc_res |= fc_network | fc_netmask_size | fc_subnet;
	}
	else
#endif
	{
		/*
		 * 4字节数据，或带有8字节数据的IPv6：使用尽可能多的
		 * 网掩码位以适应最终的简写键。避免覆盖之前设置的 ipfamily 位。
		 */
		fc_res |= fc_network >> 1;
	}

	fc_uss->input_count += 1;

	/* 哈希简写键 */
	if (fc_uss->estimating)
	{
		uint32		fc_tmp;

#if SIZEOF_DATUM == 8
		fc_tmp = (uint32) fc_res ^ (uint32) ((uint64) fc_res >> 32);
#else							/* SIZEOF_DATUM != 8 */
		tmp = (uint32) res;
#endif

		addHyperLogLog(&fc_uss->abbr_card, DatumGetUInt32(hash_uint32(fc_tmp)));
	}

	return fc_res;
}

/*
 *	布尔排序测试。
 */
Datum network_lt(PG_FUNCTION_ARGS)
{
	inet	   *fc_a1 = PG_GETARG_INET_PP(0);
	inet	   *fc_a2 = PG_GETARG_INET_PP(1);

	PG_RETURN_BOOL(fc_network_cmp_internal(fc_a1, fc_a2) < 0);
}

Datum network_le(PG_FUNCTION_ARGS)
{
	inet	   *fc_a1 = PG_GETARG_INET_PP(0);
	inet	   *fc_a2 = PG_GETARG_INET_PP(1);

	PG_RETURN_BOOL(fc_network_cmp_internal(fc_a1, fc_a2) <= 0);
}

Datum network_eq(PG_FUNCTION_ARGS)
{
	inet	   *fc_a1 = PG_GETARG_INET_PP(0);
	inet	   *fc_a2 = PG_GETARG_INET_PP(1);

	PG_RETURN_BOOL(fc_network_cmp_internal(fc_a1, fc_a2) == 0);
}

Datum network_ge(PG_FUNCTION_ARGS)
{
	inet	   *fc_a1 = PG_GETARG_INET_PP(0);
	inet	   *fc_a2 = PG_GETARG_INET_PP(1);

	PG_RETURN_BOOL(fc_network_cmp_internal(fc_a1, fc_a2) >= 0);
}

Datum network_gt(PG_FUNCTION_ARGS)
{
	inet	   *fc_a1 = PG_GETARG_INET_PP(0);
	inet	   *fc_a2 = PG_GETARG_INET_PP(1);

	PG_RETURN_BOOL(fc_network_cmp_internal(fc_a1, fc_a2) > 0);
}

Datum network_ne(PG_FUNCTION_ARGS)
{
	inet	   *fc_a1 = PG_GETARG_INET_PP(0);
	inet	   *fc_a2 = PG_GETARG_INET_PP(1);

	PG_RETURN_BOOL(fc_network_cmp_internal(fc_a1, fc_a2) != 0);
}

/*
 * MIN/MAX 支持函数。
 */
Datum network_smaller(PG_FUNCTION_ARGS)
{
	inet	   *fc_a1 = PG_GETARG_INET_PP(0);
	inet	   *fc_a2 = PG_GETARG_INET_PP(1);

	if (fc_network_cmp_internal(fc_a1, fc_a2) < 0)
		PG_RETURN_INET_P(fc_a1);
	else
		PG_RETURN_INET_P(fc_a2);
}

Datum network_larger(PG_FUNCTION_ARGS)
{
	inet	   *fc_a1 = PG_GETARG_INET_PP(0);
	inet	   *fc_a2 = PG_GETARG_INET_PP(1);

	if (fc_network_cmp_internal(fc_a1, fc_a2) > 0)
		PG_RETURN_INET_P(fc_a1);
	else
		PG_RETURN_INET_P(fc_a2);
}

/*
 * 用于 inet/cidr 的哈希索引的支持函数。
 */
Datum hashinet(PG_FUNCTION_ARGS)
{
	inet	   *fc_addr = PG_GETARG_INET_PP(0);
	int			fc_addrsize = ip_addrsize(fc_addr);

	/* XXX 这假设数据结构中没有填充字节 */
	return hash_any((unsigned char *) VARDATA_ANY(fc_addr), fc_addrsize + 2);
}

Datum hashinetextended(PG_FUNCTION_ARGS)
{
	inet	   *fc_addr = PG_GETARG_INET_PP(0);
	int			fc_addrsize = ip_addrsize(fc_addr);

	return hash_any_extended((unsigned char *) VARDATA_ANY(fc_addr), fc_addrsize + 2,
							 PG_GETARG_INT64(1));
}

/*
 * 布尔网络包含测试。
 */
Datum network_sub(PG_FUNCTION_ARGS)
{
	inet	   *fc_a1 = PG_GETARG_INET_PP(0);
	inet	   *fc_a2 = PG_GETARG_INET_PP(1);

	if (ip_family(fc_a1) == ip_family(fc_a2))
	{
		PG_RETURN_BOOL(ip_bits(fc_a1) > ip_bits(fc_a2) &&
					   bitncmp(ip_addr(fc_a1), ip_addr(fc_a2), ip_bits(fc_a2)) == 0);
	}

	PG_RETURN_BOOL(false);
}

Datum network_subeq(PG_FUNCTION_ARGS)
{
	inet	   *fc_a1 = PG_GETARG_INET_PP(0);
	inet	   *fc_a2 = PG_GETARG_INET_PP(1);

	if (ip_family(fc_a1) == ip_family(fc_a2))
	{
		PG_RETURN_BOOL(ip_bits(fc_a1) >= ip_bits(fc_a2) &&
					   bitncmp(ip_addr(fc_a1), ip_addr(fc_a2), ip_bits(fc_a2)) == 0);
	}

	PG_RETURN_BOOL(false);
}

Datum network_sup(PG_FUNCTION_ARGS)
{
	inet	   *fc_a1 = PG_GETARG_INET_PP(0);
	inet	   *fc_a2 = PG_GETARG_INET_PP(1);

	if (ip_family(fc_a1) == ip_family(fc_a2))
	{
		PG_RETURN_BOOL(ip_bits(fc_a1) < ip_bits(fc_a2) &&
					   bitncmp(ip_addr(fc_a1), ip_addr(fc_a2), ip_bits(fc_a1)) == 0);
	}

	PG_RETURN_BOOL(false);
}

Datum network_supeq(PG_FUNCTION_ARGS)
{
	inet	   *fc_a1 = PG_GETARG_INET_PP(0);
	inet	   *fc_a2 = PG_GETARG_INET_PP(1);

	if (ip_family(fc_a1) == ip_family(fc_a2))
	{
		PG_RETURN_BOOL(ip_bits(fc_a1) <= ip_bits(fc_a2) &&
					   bitncmp(ip_addr(fc_a1), ip_addr(fc_a2), ip_bits(fc_a1)) == 0);
	}

	PG_RETURN_BOOL(false);
}

Datum network_overlap(PG_FUNCTION_ARGS)
{
	inet	   *fc_a1 = PG_GETARG_INET_PP(0);
	inet	   *fc_a2 = PG_GETARG_INET_PP(1);

	if (ip_family(fc_a1) == ip_family(fc_a2))
	{
		PG_RETURN_BOOL(bitncmp(ip_addr(fc_a1), ip_addr(fc_a2),
							   Min(ip_bits(fc_a1), ip_bits(fc_a2))) == 0);
	}

	PG_RETURN_BOOL(false);
}

/*
 * 网络子集/超集运算符的规划支持函数。
 */
Datum network_subset_support(PG_FUNCTION_ARGS)
{
	Node	   *fc_rawreq = (Node *) PG_GETARG_POINTER(0);
	Node	   *fc_ret = NULL;

	if (IsA(fc_rawreq, SupportRequestIndexCondition))
	{
		/* 尝试将操作符/函数调用转换为索引条件 */
		SupportRequestIndexCondition *fc_req = (SupportRequestIndexCondition *) fc_rawreq;

		if (is_opclause(fc_req->node))
		{
			OpExpr	   *fc_clause = (OpExpr *) fc_req->node;

			Assert(list_length(fc_clause->args) == 2);
			fc_ret = (Node *)
				fc_match_network_function((Node *) linitial(fc_clause->args),
									   (Node *) lsecond(fc_clause->args),
									   fc_req->indexarg,
									   fc_req->funcid,
									   fc_req->opfamily);
		}
		else if (is_funcclause(fc_req->node))	/* 过于谨慎 */
		{
			FuncExpr   *fc_clause = (FuncExpr *) fc_req->node;

			Assert(list_length(fc_clause->args) == 2);
			fc_ret = (Node *)
				fc_match_network_function((Node *) linitial(fc_clause->args),
									   (Node *) lsecond(fc_clause->args),
									   fc_req->indexarg,
									   fc_req->funcid,
									   fc_req->opfamily);
		}
	}

	PG_RETURN_POINTER(fc_ret);
}

/*
 * match_network_function
 *	  尝试生成网络子集/超集函数的 indexqual。
 *
 * 这一层仅关注识别函数并在必要时交换参数。
 */
static List * fc_match_network_function(Node *fc_leftop,
					   Node *fc_rightop,
					   int fc_indexarg,
					   Oid fc_funcid,
					   Oid fc_opfamily)
{
	switch (fc_funcid)
	{
		case F_NETWORK_SUB:
			/* indexkey 必须在左侧 */
			if (fc_indexarg != 0)
				return NIL;
			return fc_match_network_subset(fc_leftop, fc_rightop, false, fc_opfamily);

		case F_NETWORK_SUBEQ:
			/* indexkey 必须在左侧 */
			if (fc_indexarg != 0)
				return NIL;
			return fc_match_network_subset(fc_leftop, fc_rightop, true, fc_opfamily);

		case F_NETWORK_SUP:
			/* indexkey 必须在右侧 */
			if (fc_indexarg != 1)
				return NIL;
			return fc_match_network_subset(fc_rightop, fc_leftop, false, fc_opfamily);

		case F_NETWORK_SUPEQ:
			/* indexkey 必须在右侧 */
			if (fc_indexarg != 1)
				return NIL;
			return fc_match_network_subset(fc_rightop, fc_leftop, true, fc_opfamily);

		default:

			/*
			 * 只有在有人将此支持函数附加到意外函数时我们才会到达这里。
			 * 也许我们应该抱怨，但现在不做任何事。
			 */
			return NIL;
	}
}

/*
 * match_network_subset
 *	  尝试生成网络子集函数的 indexqual。
 */
static List * fc_match_network_subset(Node *fc_leftop,
					 Node *fc_rightop,
					 bool fc_is_eq,
					 Oid fc_opfamily)
{
	List	   *fc_result;
	Datum		fc_rightopval;
	Oid			fc_datatype = INETOID;
	Oid			fc_opr1oid;
	Oid			fc_opr2oid;
	Datum		fc_opr1right;
	Datum		fc_opr2right;
	Expr	   *fc_expr;

	/*
	 * 无法对非常量或 NULL 比较值执行任何操作。
	 *
	 * 请注意，由于我们对 RHS 上的硬常量限制自己，因此它是
	 * 一个伪常量，我们不需要担心验证这一点。
	 */
	if (!IsA(fc_rightop, Const) ||
		((Const *) fc_rightop)->constisnull)
		return NIL;
	fc_rightopval = ((Const *) fc_rightop)->constvalue;

	/*
	 * 必须检查索引的 opfamily 是否支持我们想要应用的运算符。
	 *
	 * 我们坚持 opfamily 是我们预期的特定值，否则如果有人
	 * 创建一个具有相同运算符的反向排序 opfamily，我们将做错事。
	 */
	if (fc_opfamily != NETWORK_BTREE_FAM_OID)
		return NIL;

	/*
	 * 创建子句 "key >= network_scan_first( rightopval )"，如果运算符
	 * 不允许相等则为 ">"。
	 *
	 * 注意：考虑到此函数仅支持 opfamily 和数据类型的固定值，
	 * 我们本可以直接硬连线运算符 OID，而不是进行查找。
	 * 但现在似乎更好的是保持通用性。
	 */
	if (fc_is_eq)
	{
		fc_opr1oid = get_opfamily_member(fc_opfamily, fc_datatype, fc_datatype,
									  BTGreaterEqualStrategyNumber);
		if (fc_opr1oid == InvalidOid)
			elog(ERROR, "no >= operator for opfamily %u", fc_opfamily);
	}
	else
	{
		fc_opr1oid = get_opfamily_member(fc_opfamily, fc_datatype, fc_datatype,
									  BTGreaterStrategyNumber);
		if (fc_opr1oid == InvalidOid)
			elog(ERROR, "no > operator for opfamily %u", fc_opfamily);
	}

	fc_opr1right = network_scan_first(fc_rightopval);

	fc_expr = make_opclause(fc_opr1oid, BOOLOID, false,
						 (Expr *) fc_leftop,
						 (Expr *) makeConst(fc_datatype, -1,
											InvalidOid, /* 不可比较 */
											-1, fc_opr1right,
											false, false),
						 InvalidOid, InvalidOid);
	fc_result = list_make1(fc_expr);

	/* 创建子句 "key <= network_scan_last( rightopval )" */

	fc_opr2oid = get_opfamily_member(fc_opfamily, fc_datatype, fc_datatype,
								  BTLessEqualStrategyNumber);
	if (fc_opr2oid == InvalidOid)
		elog(ERROR, "no <= operator for opfamily %u", fc_opfamily);

	fc_opr2right = network_scan_last(fc_rightopval);

	fc_expr = make_opclause(fc_opr2oid, BOOLOID, false,
						 (Expr *) fc_leftop,
						 (Expr *) makeConst(fc_datatype, -1,
											InvalidOid, /* 不可比较 */
											-1, fc_opr2right,
											false, false),
						 InvalidOid, InvalidOid);
	fc_result = lappend(fc_result, fc_expr);

	return fc_result;
}


/*
 * 从网络数据类型中提取数据。
 */
Datum network_host(PG_FUNCTION_ARGS)
{
	inet	   *fc_ip = PG_GETARG_INET_PP(0);
	char	   *fc_ptr;
	char		fc_tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];

	/* 强制显示最大位数，无论 masklen... */
	if (pg_inet_net_ntop(ip_family(fc_ip), ip_addr(fc_ip), ip_maxbits(fc_ip),
						 fc_tmp, sizeof(fc_tmp)) == NULL)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
				 errmsg("could not format inet value: %m")));

	/* 如果存在则抑制 /n（现在不应发生） */
	if ((fc_ptr = strchr(fc_tmp, '/')) != NULL)
		*fc_ptr = '\0';

	PG_RETURN_TEXT_P(cstring_to_text(fc_tmp));
}

/*
 * network_show 实现 inet 和 cidr 到文本的转换。这并不
 * 完全等同于 network_out，因此我们不能为 CoerceViaIO
 * 丢弃它。
 */
Datum network_show(PG_FUNCTION_ARGS)
{
	inet	   *fc_ip = PG_GETARG_INET_PP(0);
	int			fc_len;
	char		fc_tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];

	if (pg_inet_net_ntop(ip_family(fc_ip), ip_addr(fc_ip), ip_maxbits(fc_ip),
						 fc_tmp, sizeof(fc_tmp)) == NULL)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
				 errmsg("could not format inet value: %m")));

	/* 如果不存在则添加 /n（它肯定不会存在） */
	if (strchr(fc_tmp, '/') == NULL)
	{
		fc_len = strlen(fc_tmp);
		snprintf(fc_tmp + fc_len, sizeof(fc_tmp) - fc_len, "/%u", ip_bits(fc_ip));
	}

	PG_RETURN_TEXT_P(cstring_to_text(fc_tmp));
}

Datum inet_abbrev(PG_FUNCTION_ARGS)
{
	inet	   *fc_ip = PG_GETARG_INET_PP(0);
	char	   *fc_dst;
	char		fc_tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];

	fc_dst = pg_inet_net_ntop(ip_family(fc_ip), ip_addr(fc_ip),
						   ip_bits(fc_ip), fc_tmp, sizeof(fc_tmp));

	if (fc_dst == NULL)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
				 errmsg("could not format inet value: %m")));

	PG_RETURN_TEXT_P(cstring_to_text(fc_tmp));
}

Datum cidr_abbrev(PG_FUNCTION_ARGS)
{
	inet	   *fc_ip = PG_GETARG_INET_PP(0);
	char	   *fc_dst;
	char		fc_tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];

	fc_dst = pg_inet_cidr_ntop(ip_family(fc_ip), ip_addr(fc_ip),
							ip_bits(fc_ip), fc_tmp, sizeof(fc_tmp));

	if (fc_dst == NULL)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
				 errmsg("could not format cidr value: %m")));

	PG_RETURN_TEXT_P(cstring_to_text(fc_tmp));
}

Datum network_masklen(PG_FUNCTION_ARGS)
{
	inet	   *fc_ip = PG_GETARG_INET_PP(0);

	PG_RETURN_INT32(ip_bits(fc_ip));
}

Datum network_family(PG_FUNCTION_ARGS)
{
	inet	   *fc_ip = PG_GETARG_INET_PP(0);

	switch (ip_family(fc_ip))
	{
		case PGSQL_AF_INET:
			PG_RETURN_INT32(4);
			break;
		case PGSQL_AF_INET6:
			PG_RETURN_INT32(6);
			break;
		default:
			PG_RETURN_INT32(0);
			break;
	}
}

Datum network_broadcast(PG_FUNCTION_ARGS)
{
	inet	   *fc_ip = PG_GETARG_INET_PP(0);
	inet	   *fc_dst;
	int			fc_byte;
	int			fc_bits;
	int			fc_maxbytes;
	unsigned char fc_mask;
	unsigned char *fc_a,
			   *fc_b;

	/* 确保任何未使用的位都被清零 */
	fc_dst = (inet *) palloc0(sizeof(inet));

	fc_maxbytes = ip_addrsize(fc_ip);
	fc_bits = ip_bits(fc_ip);
	fc_a = ip_addr(fc_ip);
	fc_b = ip_addr(fc_dst);

	for (fc_byte = 0; fc_byte < fc_maxbytes; fc_byte++)
	{
		if (fc_bits >= 8)
		{
			fc_mask = 0x00;
			fc_bits -= 8;
		}
		else if (fc_bits == 0)
			fc_mask = 0xff;
		else
		{
			fc_mask = 0xff >> fc_bits;
			fc_bits = 0;
		}

		fc_b[fc_byte] = fc_a[fc_byte] | fc_mask;
	}

	ip_family(fc_dst) = ip_family(fc_ip);
	ip_bits(fc_dst) = ip_bits(fc_ip);
	SET_INET_VARSIZE(fc_dst);

	PG_RETURN_INET_P(fc_dst);
}

Datum network_network(PG_FUNCTION_ARGS)
{
	inet	   *fc_ip = PG_GETARG_INET_PP(0);
	inet	   *fc_dst;
	int			fc_byte;
	int			fc_bits;
	unsigned char fc_mask;
	unsigned char *fc_a,
			   *fc_b;

	/* 确保任何未使用的位都被清零 */
	fc_dst = (inet *) palloc0(sizeof(inet));

	fc_bits = ip_bits(fc_ip);
	fc_a = ip_addr(fc_ip);
	fc_b = ip_addr(fc_dst);

	fc_byte = 0;

	while (fc_bits)
	{
		if (fc_bits >= 8)
		{
			fc_mask = 0xff;
			fc_bits -= 8;
		}
		else
		{
			fc_mask = 0xff << (8 - fc_bits);
			fc_bits = 0;
		}

		fc_b[fc_byte] = fc_a[fc_byte] & fc_mask;
		fc_byte++;
	}

	ip_family(fc_dst) = ip_family(fc_ip);
	ip_bits(fc_dst) = ip_bits(fc_ip);
	SET_INET_VARSIZE(fc_dst);

	PG_RETURN_INET_P(fc_dst);
}

Datum network_netmask(PG_FUNCTION_ARGS)
{
	inet	   *fc_ip = PG_GETARG_INET_PP(0);
	inet	   *fc_dst;
	int			fc_byte;
	int			fc_bits;
	unsigned char fc_mask;
	unsigned char *fc_b;

	/* 确保任何未使用的位都被清零 */
	fc_dst = (inet *) palloc0(sizeof(inet));

	fc_bits = ip_bits(fc_ip);
	fc_b = ip_addr(fc_dst);

	fc_byte = 0;

	while (fc_bits)
	{
		if (fc_bits >= 8)
		{
			fc_mask = 0xff;
			fc_bits -= 8;
		}
		else
		{
			fc_mask = 0xff << (8 - fc_bits);
			fc_bits = 0;
		}

		fc_b[fc_byte] = fc_mask;
		fc_byte++;
	}

	ip_family(fc_dst) = ip_family(fc_ip);
	ip_bits(fc_dst) = ip_maxbits(fc_ip);
	SET_INET_VARSIZE(fc_dst);

	PG_RETURN_INET_P(fc_dst);
}

Datum network_hostmask(PG_FUNCTION_ARGS)
{
	inet	   *fc_ip = PG_GETARG_INET_PP(0);
	inet	   *fc_dst;
	int			fc_byte;
	int			fc_bits;
	int			fc_maxbytes;
	unsigned char fc_mask;
	unsigned char *fc_b;

	/* 确保任何未使用的位都被清零 */
	fc_dst = (inet *) palloc0(sizeof(inet));

	fc_maxbytes = ip_addrsize(fc_ip);
	fc_bits = ip_maxbits(fc_ip) - ip_bits(fc_ip);
	fc_b = ip_addr(fc_dst);

	fc_byte = fc_maxbytes - 1;

	while (fc_bits)
	{
		if (fc_bits >= 8)
		{
			fc_mask = 0xff;
			fc_bits -= 8;
		}
		else
		{
			fc_mask = 0xff >> (8 - fc_bits);
			fc_bits = 0;
		}

		fc_b[fc_byte] = fc_mask;
		fc_byte--;
	}

	ip_family(fc_dst) = ip_family(fc_ip);
	ip_bits(fc_dst) = ip_maxbits(fc_ip);
	SET_INET_VARSIZE(fc_dst);

	PG_RETURN_INET_P(fc_dst);
}

/*
 * 如果地址来自同一系列则返回 true，否则返回 false。用于
 * 检查我们是否可以创建一个包含两个网络的网络。
 */
Datum inet_same_family(PG_FUNCTION_ARGS)
{
	inet	   *fc_a1 = PG_GETARG_INET_PP(0);
	inet	   *fc_a2 = PG_GETARG_INET_PP(1);

	PG_RETURN_BOOL(ip_family(fc_a1) == ip_family(fc_a2));
}

/*
 * 返回包含两个输入的最小 CIDR。
 */
Datum inet_merge(PG_FUNCTION_ARGS)
{
	inet	   *fc_a1 = PG_GETARG_INET_PP(0),
			   *fc_a2 = PG_GETARG_INET_PP(1);
	int			fc_commonbits;

	if (ip_family(fc_a1) != ip_family(fc_a2))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("cannot merge addresses from different families")));

	fc_commonbits = bitncommon(ip_addr(fc_a1), ip_addr(fc_a2),
							Min(ip_bits(fc_a1), ip_bits(fc_a2)));

	PG_RETURN_INET_P(cidr_set_masklen_internal(fc_a1, fc_commonbits));
}

/*
 * 将网络数据类型的值转换为近似标量值。
 * 这用于估计涉及网络类型的不等式运算符的选择性。
 *
 * 在失败时（例如，未支持的 typid），将 *failure 设置为 true；
 * 否则，该变量不进行更改。
 */
double convert_network_to_scalar(Datum fc_value, Oid fc_typid, bool *fc_failure)
{
	switch (fc_typid)
	{
		case INETOID:
		case CIDROID:
			{
				inet	   *fc_ip = DatumGetInetPP(fc_value);
				int			fc_len;
				double		fc_res;
				int			fc_i;

				/*
				 * 注意，我们不使用完整的IPv6地址。
				 */
				if (ip_family(fc_ip) == PGSQL_AF_INET)
					fc_len = 4;
				else
					fc_len = 5;

				fc_res = ip_family(fc_ip);
				for (fc_i = 0; fc_i < fc_len; fc_i++)
				{
					fc_res *= 256;
					fc_res += ip_addr(fc_ip)[fc_i];
				}
				return fc_res;
			}
		case MACADDROID:
			{
				macaddr    *fc_mac = DatumGetMacaddrP(fc_value);
				double		fc_res;

				fc_res = (fc_mac->a << 16) | (fc_mac->b << 8) | (fc_mac->c);
				fc_res *= 256 * 256 * 256;
				fc_res += (fc_mac->d << 16) | (fc_mac->e << 8) | (fc_mac->f);
				return fc_res;
			}
		case MACADDR8OID:
			{
				macaddr8   *fc_mac = DatumGetMacaddr8P(fc_value);
				double		fc_res;

				fc_res = (fc_mac->a << 24) | (fc_mac->b << 16) | (fc_mac->c << 8) | (fc_mac->d);
				fc_res *= ((double) 256) * 256 * 256 * 256;
				fc_res += (fc_mac->e << 24) | (fc_mac->f << 16) | (fc_mac->g << 8) | (fc_mac->h);
				return fc_res;
			}
	}

	*fc_failure = true;
	return 0;
}

/*
 * int
 * bitncmp(l, r, n)
 *		比较位掩码l和r，比较n位。
 * 返回：
 *		<0，>0，或遵循libc传统的0。
 * 注意：
 *		假定网络字节顺序。这意味着192.5.5.240/28在其第四个八位字节中有
 *		0x11110000。
 * 作者：
 *		Paul Vixie (ISC)，1996年6月
 */
int bitncmp(const unsigned char *fc_l, const unsigned char *fc_r, int fc_n)
{
	unsigned int fc_lb,
				fc_rb;
	int			fc_x,
				fc_b;

	fc_b = fc_n / 8;
	fc_x = memcmp(fc_l, fc_r, fc_b);
	if (fc_x || (fc_n % 8) == 0)
		return fc_x;

	fc_lb = fc_l[fc_b];
	fc_rb = fc_r[fc_b];
	for (fc_b = fc_n % 8; fc_b > 0; fc_b--)
	{
		if (IS_HIGHBIT_SET(fc_lb) != IS_HIGHBIT_SET(fc_rb))
		{
			if (IS_HIGHBIT_SET(fc_lb))
				return 1;
			return -1;
		}
		fc_lb <<= 1;
		fc_rb <<= 1;
	}
	return 0;
}

/*
 * bitncommon: 比较位掩码l和r，最多n位。
 *
 * 返回匹配的前导位数（0到n）。
 */
int bitncommon(const unsigned char *fc_l, const unsigned char *fc_r, int fc_n)
{
	int			fc_byte,
				fc_nbits;

	/* 最后一个字节中要检查的位数 */
	fc_nbits = fc_n % 8;

	/* 检查整个字节 */
	for (fc_byte = 0; fc_byte < fc_n / 8; fc_byte++)
	{
		if (fc_l[fc_byte] != fc_r[fc_byte])
		{
			/* 最后一个字节中至少有一个位不是公共的 */
			fc_nbits = 7;
			break;
		}
	}

	/* 检查最后一个部分字节中的位 */
	if (fc_nbits != 0)
	{
		/* 计算第一个不匹配字节的差 */
		unsigned int fc_diff = fc_l[fc_byte] ^ fc_r[fc_byte];

		/* 从高到低比较比特 */
		while ((fc_diff >> (8 - fc_nbits)) != 0)
			fc_nbits--;
	}

	return (8 * fc_byte) + fc_nbits;
}


/*
 * 验证 CIDR 地址是否正常（没有超出 masklen 设置的位）
 */
static bool fc_addressOK(unsigned char *fc_a, int fc_bits, int fc_family)
{
	int			fc_byte;
	int			fc_nbits;
	int			fc_maxbits;
	int			fc_maxbytes;
	unsigned char fc_mask;

	if (fc_family == PGSQL_AF_INET)
	{
		fc_maxbits = 32;
		fc_maxbytes = 4;
	}
	else
	{
		fc_maxbits = 128;
		fc_maxbytes = 16;
	}
	Assert(fc_bits <= fc_maxbits);

	if (fc_bits == fc_maxbits)
		return true;

	fc_byte = fc_bits / 8;

	fc_nbits = fc_bits % 8;
	fc_mask = 0xff;
	if (fc_bits != 0)
		fc_mask >>= fc_nbits;

	while (fc_byte < fc_maxbytes)
	{
		if ((fc_a[fc_byte] & fc_mask) != 0)
			return false;
		fc_mask = 0xff;
		fc_byte++;
	}

	return true;
}


/*
 * 这些函数由规划器用于生成索引扫描限制
 * 用于子句 a << b 和 a <<= b
 */

/* 返回给定网络上 IP 的最小值 */
Datum network_scan_first(Datum fc_in)
{
	return DirectFunctionCall1(network_network, fc_in);
}

/*
 * 返回给定网络上的“最后” IP。它是广播地址，
 * 然而，masklen 必须设置为其最大位数，因为
 * 192.168.0.255/24 被认为小于 192.168.0.255/32
 *
 * inet_set_masklen() 被修改为将 IPv6 的掩码长度最大化到 128，
 * 将 IPv4 的掩码长度最大化到 32，当给定 '-1' 作为参数时。
 */
Datum network_scan_last(Datum fc_in)
{
	return DirectFunctionCall2(inet_set_masklen,
							   DirectFunctionCall1(network_broadcast, fc_in),
							   Int32GetDatum(-1));
}


/*
 * 客户端连接的 IP 地址（如果是 Unix 套接字，则为 NULL）
 */
Datum inet_client_addr(PG_FUNCTION_ARGS)
{
	Port	   *fc_port = MyProcPort;
	char		fc_remote_host[NI_MAXHOST];
	int			fc_ret;

	if (fc_port == NULL)
		PG_RETURN_NULL();

	switch (fc_port->raddr.addr.ss_family)
	{
		case AF_INET:
#ifdef HAVE_IPV6
		case AF_INET6:
#endif
			break;
		default:
			PG_RETURN_NULL();
	}

	fc_remote_host[0] = '\0';

	fc_ret = pg_getnameinfo_all(&fc_port->raddr.addr, fc_port->raddr.salen,
							 fc_remote_host, sizeof(fc_remote_host),
							 NULL, 0,
							 NI_NUMERICHOST | NI_NUMERICSERV);
	if (fc_ret != 0)
		PG_RETURN_NULL();

	clean_ipv6_addr(fc_port->raddr.addr.ss_family, fc_remote_host);

	PG_RETURN_INET_P(fc_network_in(fc_remote_host, false));
}


/*
 * 客户端连接的端口（如果是 Unix 套接字，则为 NULL）
 */
Datum inet_client_port(PG_FUNCTION_ARGS)
{
	Port	   *fc_port = MyProcPort;
	char		fc_remote_port[NI_MAXSERV];
	int			fc_ret;

	if (fc_port == NULL)
		PG_RETURN_NULL();

	switch (fc_port->raddr.addr.ss_family)
	{
		case AF_INET:
#ifdef HAVE_IPV6
		case AF_INET6:
#endif
			break;
		default:
			PG_RETURN_NULL();
	}

	fc_remote_port[0] = '\0';

	fc_ret = pg_getnameinfo_all(&fc_port->raddr.addr, fc_port->raddr.salen,
							 NULL, 0,
							 fc_remote_port, sizeof(fc_remote_port),
							 NI_NUMERICHOST | NI_NUMERICSERV);
	if (fc_ret != 0)
		PG_RETURN_NULL();

	PG_RETURN_DATUM(DirectFunctionCall1(int4in, CStringGetDatum(fc_remote_port)));
}


/*
 * 服务器接受连接的 IP 地址（如果是 Unix 套接字，则为 NULL）
 */
Datum inet_server_addr(PG_FUNCTION_ARGS)
{
	Port	   *fc_port = MyProcPort;
	char		fc_local_host[NI_MAXHOST];
	int			fc_ret;

	if (fc_port == NULL)
		PG_RETURN_NULL();

	switch (fc_port->laddr.addr.ss_family)
	{
		case AF_INET:
#ifdef HAVE_IPV6
		case AF_INET6:
#endif
			break;
		default:
			PG_RETURN_NULL();
	}

	fc_local_host[0] = '\0';

	fc_ret = pg_getnameinfo_all(&fc_port->laddr.addr, fc_port->laddr.salen,
							 fc_local_host, sizeof(fc_local_host),
							 NULL, 0,
							 NI_NUMERICHOST | NI_NUMERICSERV);
	if (fc_ret != 0)
		PG_RETURN_NULL();

	clean_ipv6_addr(fc_port->laddr.addr.ss_family, fc_local_host);

	PG_RETURN_INET_P(fc_network_in(fc_local_host, false));
}


/*
 * 服务器接受连接的端口（如果是 Unix 套接字则为 NULL）
 */
Datum inet_server_port(PG_FUNCTION_ARGS)
{
	Port	   *fc_port = MyProcPort;
	char		fc_local_port[NI_MAXSERV];
	int			fc_ret;

	if (fc_port == NULL)
		PG_RETURN_NULL();

	switch (fc_port->laddr.addr.ss_family)
	{
		case AF_INET:
#ifdef HAVE_IPV6
		case AF_INET6:
#endif
			break;
		default:
			PG_RETURN_NULL();
	}

	fc_local_port[0] = '\0';

	fc_ret = pg_getnameinfo_all(&fc_port->laddr.addr, fc_port->laddr.salen,
							 NULL, 0,
							 fc_local_port, sizeof(fc_local_port),
							 NI_NUMERICHOST | NI_NUMERICSERV);
	if (fc_ret != 0)
		PG_RETURN_NULL();

	PG_RETURN_DATUM(DirectFunctionCall1(int4in, CStringGetDatum(fc_local_port)));
}


Datum inetnot(PG_FUNCTION_ARGS)
{
	inet	   *fc_ip = PG_GETARG_INET_PP(0);
	inet	   *fc_dst;

	fc_dst = (inet *) palloc0(sizeof(inet));

	{
		int			fc_nb = ip_addrsize(fc_ip);
		unsigned char *fc_pip = ip_addr(fc_ip);
		unsigned char *fc_pdst = ip_addr(fc_dst);

		while (--fc_nb >= 0)
			fc_pdst[fc_nb] = ~fc_pip[fc_nb];
	}
	ip_bits(fc_dst) = ip_bits(fc_ip);

	ip_family(fc_dst) = ip_family(fc_ip);
	SET_INET_VARSIZE(fc_dst);

	PG_RETURN_INET_P(fc_dst);
}


Datum inetand(PG_FUNCTION_ARGS)
{
	inet	   *fc_ip = PG_GETARG_INET_PP(0);
	inet	   *fc_ip2 = PG_GETARG_INET_PP(1);
	inet	   *fc_dst;

	fc_dst = (inet *) palloc0(sizeof(inet));

	if (ip_family(fc_ip) != ip_family(fc_ip2))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("cannot AND inet values of different sizes")));
	else
	{
		int			fc_nb = ip_addrsize(fc_ip);
		unsigned char *fc_pip = ip_addr(fc_ip);
		unsigned char *fc_pip2 = ip_addr(fc_ip2);
		unsigned char *fc_pdst = ip_addr(fc_dst);

		while (--fc_nb >= 0)
			fc_pdst[fc_nb] = fc_pip[fc_nb] & fc_pip2[fc_nb];
	}
	ip_bits(fc_dst) = Max(ip_bits(fc_ip), ip_bits(fc_ip2));

	ip_family(fc_dst) = ip_family(fc_ip);
	SET_INET_VARSIZE(fc_dst);

	PG_RETURN_INET_P(fc_dst);
}


Datum inetor(PG_FUNCTION_ARGS)
{
	inet	   *fc_ip = PG_GETARG_INET_PP(0);
	inet	   *fc_ip2 = PG_GETARG_INET_PP(1);
	inet	   *fc_dst;

	fc_dst = (inet *) palloc0(sizeof(inet));

	if (ip_family(fc_ip) != ip_family(fc_ip2))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("cannot OR inet values of different sizes")));
	else
	{
		int			fc_nb = ip_addrsize(fc_ip);
		unsigned char *fc_pip = ip_addr(fc_ip);
		unsigned char *fc_pip2 = ip_addr(fc_ip2);
		unsigned char *fc_pdst = ip_addr(fc_dst);

		while (--fc_nb >= 0)
			fc_pdst[fc_nb] = fc_pip[fc_nb] | fc_pip2[fc_nb];
	}
	ip_bits(fc_dst) = Max(ip_bits(fc_ip), ip_bits(fc_ip2));

	ip_family(fc_dst) = ip_family(fc_ip);
	SET_INET_VARSIZE(fc_dst);

	PG_RETURN_INET_P(fc_dst);
}


static inet * fc_internal_inetpl(inet *fc_ip, int64 fc_addend)
{
	inet	   *fc_dst;

	fc_dst = (inet *) palloc0(sizeof(inet));

	{
		int			fc_nb = ip_addrsize(fc_ip);
		unsigned char *fc_pip = ip_addr(fc_ip);
		unsigned char *fc_pdst = ip_addr(fc_dst);
		int			fc_carry = 0;

		while (--fc_nb >= 0)
		{
			fc_carry = fc_pip[fc_nb] + (int) (fc_addend & 0xFF) + fc_carry;
			fc_pdst[fc_nb] = (unsigned char) (fc_carry & 0xFF);
			fc_carry >>= 8;

			/*
			 * 我们必须小心加数的右移，因为
			 * 右移在负值下并不可移植，而简单地
			 * 除以 256 不行（标准舍入方向是
			 * 错误的，而且可能有机器
			 * 向错误的方向舍入）。因此，明确清除低位
			 * 字节以消除关于
			 * 除法正确结果的任何疑虑，然后进行除法而不是右移。
			 */
			fc_addend &= ~((int64) 0xFF);
			fc_addend /= 0x100;
		}

		/*
		 * 此时，如果原始加数 >= 0，我们应该加数和进位均为零，
		 * 或者如果原始加数 < 0，加数为 -1，进位为 1。
		 * 其他任何情况都意味着溢出。
		 */
		if (!((fc_addend == 0 && fc_carry == 0) ||
			  (fc_addend == -1 && fc_carry == 1)))
			ereport(ERROR,
					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
					 errmsg("result is out of range")));
	}

	ip_bits(fc_dst) = ip_bits(fc_ip);
	ip_family(fc_dst) = ip_family(fc_ip);
	SET_INET_VARSIZE(fc_dst);

	return fc_dst;
}


Datum inetpl(PG_FUNCTION_ARGS)
{
	inet	   *fc_ip = PG_GETARG_INET_PP(0);
	int64		fc_addend = PG_GETARG_INT64(1);

	PG_RETURN_INET_P(fc_internal_inetpl(fc_ip, fc_addend));
}


Datum inetmi_int8(PG_FUNCTION_ARGS)
{
	inet	   *fc_ip = PG_GETARG_INET_PP(0);
	int64		fc_addend = PG_GETARG_INT64(1);

	PG_RETURN_INET_P(fc_internal_inetpl(fc_ip, -fc_addend));
}


Datum inetmi(PG_FUNCTION_ARGS)
{
	inet	   *fc_ip = PG_GETARG_INET_PP(0);
	inet	   *fc_ip2 = PG_GETARG_INET_PP(1);
	int64		fc_res = 0;

	if (ip_family(fc_ip) != ip_family(fc_ip2))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("cannot subtract inet values of different sizes")));
	else
	{
		/*
		 * 我们使用传统的补码、增量和加法规则形成差值，
		 * 增量部分通过将进位初始值设置为 1 来处理。
		 * 如果你认为整数算术是在
		 * 二进制补码中完成的，那就太糟糕了。
		 */
		int			fc_nb = ip_addrsize(fc_ip);
		int			fc_byte = 0;
		unsigned char *fc_pip = ip_addr(fc_ip);
		unsigned char *fc_pip2 = ip_addr(fc_ip2);
		int			fc_carry = 1;

		while (--fc_nb >= 0)
		{
			int			fc_lobyte;

			fc_carry = fc_pip[fc_nb] + (~fc_pip2[fc_nb] & 0xFF) + fc_carry;
			fc_lobyte = fc_carry & 0xFF;
			if (fc_byte < sizeof(int64))
			{
				fc_res |= ((int64) fc_lobyte) << (fc_byte * 8);
			}
			else
			{
				/*
				 * 输入宽于 int64：检查溢出。应该是适合的左边
				 * 所有字节都应为 0 或 0xFF，这取决于
				 * 现已完成结果的符号。
				 */
				if ((fc_res < 0) ? (fc_lobyte != 0xFF) : (fc_lobyte != 0))
					ereport(ERROR,
							(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
							 errmsg("result is out of range")));
			}
			fc_carry >>= 8;
			fc_byte++;
		}

		/*
		 * 如果输入窄于 int64，则不可能发生溢出，但我们
		 * 必须做好适当的符号扩展。
		 */
		if (fc_carry == 0 && fc_byte < sizeof(int64))
			fc_res |= ((uint64) (int64) -1) << (fc_byte * 8);
	}

	PG_RETURN_INT64(fc_res);
}


/*
 * clean_ipv6_addr --- 从 IPv6 地址字符串中移除任何 '%zone' 部分
 *
 * XXX 这应该在某一天消失！
 *
 * 这是一个权宜之计，因为我们尚未支持存储的 inet
 * 值中的区域。由于 getnameinfo() 的结果可能包含区域规格，
 * 因此在我们想将 getnameinfo 的输出传递给
 * network_in 的任何地方调用此方法以移除它。总比完全失败要好。
 *
 * 另一种方法是让 network_in 自行忽略 %-部分，
 * 但这意味着我们将在用户输入中默默丢弃区域规格，
 * 这似乎不是个好主意。
 */
void clean_ipv6_addr(int fc_addr_family, char *fc_addr)
{
#ifdef HAVE_IPV6
	if (fc_addr_family == AF_INET6)
	{
		char	   *fc_pct = strchr(fc_addr, '%');

		if (fc_pct)
			*fc_pct = '\0';
	}
#endif
}
